
// for 'or' 'and', 
// 'or' is to find the first valid var witch is not err/none, 
// so, if check all the var, and no err/none or all err/none, then return the lastest valid var
// 'and' is to find the first err/none, 

const V_DEFAULT: u32 = 1;

fn main() {
    println!("Hello, world!");

    //test_or_and();
    //test_orelse();
    //test_andthen();

    //test_filter();
    //test_map();

    // test_map_err();
    // test_map_or();
    // test_map_or_else();

    // test_ok_or();
    test_ok_or_else();
}

// check 1
fn test_or_and() {
    let s1 = Some("s1");
    let s2 = Some("s2");
    let n: Option<&str> = None;

    let o1: Result<&str, &str> = Ok("ok1");
    let o2: Result<&str, &str> = Ok("ok2");

    let e1: Result<&str, &str> = Err("e1");
    let e2: Result<&str, &str> = Err("e2");
    let e3: Result<&str, &str> = Err("e3");

    // methood var type should same
    // for 'or' can ordered check the var, which is not none/err, return that var 
    assert_eq!(s1.or(s2), s1);
    assert_eq!(n.or(s2), s2);

    assert_eq!(o1.or(o2), o1);
    assert_eq!(e1.or(o2), o2);

    // for 'or', if all err, return the latest err
    assert_eq!(e1.or(e2), e2);
    assert_eq!(e1.or(e2).or(e3), e3);

    // for 'and', check all the var, if (all Some and Ok), return the lastest var 
    // else return the first none/err include all err or none,
    assert_eq!(s1.and(s2), s2);
    assert_eq!(n.and(s2), n);    

    assert_eq!(n.and(n).and(s1), None);

    assert_eq!(o1.and(o2), o2);
    assert_eq!(e1.and(o2), e1);

    assert_eq!(e1.and(e2), e1);
    assert_eq!(e1.and(e2).and(e3), e1);
    assert_eq!(o1.and(e1).and(e2), e1);

    //assert_eq!(s1.or(o1), s1);
}

// test the fn for the type option
fn test_orelse() {
    let s1 = Some("s1");
    let s2 = Some("s2");
    
    let fn_some = || Some("s2");
    // equal: 
    // let fn_some = || -> Option<&str> { Some("s2") };

    let n: Option<&str> = None;
    let fn_n = || -> Option<&str> { None };

    assert_eq!(s1.or_else(fn_some), s1);
    assert_eq!(n.or_else(fn_n), n);
    assert_eq!(n.or_else(fn_n), None);
    //assert_eq!(n.or_else(fn_some), None);

    let o1: Result<&str, &str> = Ok("o1");  
    let o2: Result<&str, &str> = Ok("o2");  
    let fn_ok = |_:&str| -> Result<&str, &str> { Ok("o2") };
    

    let e1: Result<&str, &str> = Err("e1");
    let e2: Result<&str, &str> = Err("e2");
    let fn_err = |_:&str| -> Result<&str, &str> {Err("e2")};

    assert_eq!(o1.or_else(fn_ok), o1);
    assert_eq!(e1.or_else(fn_ok), o2);    
    assert_eq!(e1.or_else(fn_err), e2);
}

fn test_andthen() {
    let s1 = Some("s1");
    let s2 = Some("s2");
    
    let fn_some = |_| Some("s2");
    // equal: 
    // let fn_some = || -> Option<&str> { Some("s2") };

    let n: Option<&str> = None;
    let fn_n = |_:&str| -> Option<&str> { None };

    let o1: Result<&str, &str> = Ok("o1");  
    let o2: Result<&str, &str> = Ok("o2");  
    let fn_ok = |_:&str| -> Result<&str, &str> { Ok("o2") };
    

    let e1: Result<&str, &str> = Err("e1");
    let e2: Result<&str, &str> = Err("e2");
    let fn_err = |_:&str| -> Result<&str, &str> {Err("e2")};

    assert_eq!(s1.and_then(fn_some), s2);
    assert_eq!(s1.and_then(fn_n), n);

    assert_eq!(o1.and_then(fn_ok), o2);
    assert_eq!(o1.and(e1).and_then(fn_ok), e1);    
    assert_eq!(e1.and_then(fn_err), e1);
    assert_eq!(o1.and_then(fn_err).and(e1).and_then(fn_ok), e2);   
}

fn test_filter(){
    let s1 = Some(6);
    let s2 = Some(5);
    let n: Option<i8> = None;

    let fn_is_even = |x: &i8| x % 2 == 0;

    assert_eq!(s1.filter(fn_is_even), s1);
    assert_eq!(s2.filter(fn_is_even), n);
}

fn test_map() {
    let s1: Option<&str> = Some("abcd");
    let s2: Option<usize> = Some(4);

    let n1: Option<&str> = None;
    let n2: Option<usize> = None;

    let o1: Result<&str, &str> = Ok("abc");
    let o2: Result<usize, &str> = Ok(3);

    let e1: Result<&str, &str> = Err("abcde");
    let e2: Result<usize, &str> = Err("abcde");
    // let e3: Result<usize, usize> = Err(5);

    let fn_c_count = |s:&str| s.chars().count();

    assert_eq!(s1.map(fn_c_count), s2);
    assert_eq!(n1.map(fn_c_count), n2);

    assert_eq!(o1.map(fn_c_count), o2);
    assert_eq!(e1.map(fn_c_count), e2);
    //assert_eq!(e1.map(fn_c_count), e3);
}

fn test_map_err() {

    let o1: Result<&str, &str> = Ok("abc");
    let o2: Result<&str, isize> = Ok("abc");

    let e1: Result<&str, &str> = Err("404");
    let e2: Result<&str, isize> = Err(404);

    let fn_c_count = |s:&str| -> isize { s.parse().unwrap() };

    assert_eq!(o1.map_err(fn_c_count), o2);

    assert_eq!(e1.map_err(fn_c_count), e2);
}

fn test_map_or() {
    // let r: Result<u32, ()> = Ok(10);
    let r: Result<u32, &str> = Ok(10);
    // let r2: Result<u32, ()> = Err(());
    let n: Option<u32> = None;

    let fn_closure = |v: u32| v + 2;

    assert_eq!(r.map_or(V_DEFAULT, fn_closure), 12);
    assert_eq!(n.map_or(V_DEFAULT, fn_closure), V_DEFAULT);    
}

// the key point is the invoke var's T. Option is diff from Result.
fn test_map_or_else() {

    let fn_closure = |v: i8| v + 2;

    let s: Option<i8> = Some(5);    
    let n: Option<i8> = None;
    // for option, it only invoke var, and can no input for fn_closure  
    // this default, target on None. so it should not have input. just match the T (Option<T> var which invoke this fn ) is ok.
    let fn_default = || 3; 

    assert_eq!(s.map_or_else(fn_default, fn_closure), 7);
    assert_eq!(n.map_or_else(fn_default, fn_closure), 3);

    // for result, default fn, should have one input for error part of result.   
    // let r: Result<u32, ()> = Ok(10);
    let r: Result<i8, i8> = Ok(10);
    // let r2: Result<u32, ()> = Err(());
    let r2: Result<i8, i8> = Err(6);
    // this default, target on Error. so it should have one input which is the err. and the input T should match the Result<U, T>, the Err(T).
    let fn_def_result = |a: i8| a + 3;

    assert_eq!(r.map_or_else(fn_def_result, fn_closure), 12);
    assert_eq!(r2.map_or_else(fn_def_result, fn_closure), 9);
}

fn test_ok_or() {

    const DEFAULT_I8:i8 = 99;

    let s1: Option<i8> = Some(1);
    let n: Option<i8> = None;

    let o1: Result<i8, i8> = Ok(1);
    let r1: Result<i8, i8> = Err(99);

    // default T should match the Result part.
    assert_eq!(s1.ok_or(DEFAULT_I8), o1);
    assert_eq!(n.ok_or(DEFAULT_I8), r1);
}

fn test_ok_or_else() {
    
    let s1: Option<&str> = Some("abc");
    let n: Option<&str> = None;

    let fn_err = || "err";

    let o1: Result<&str, &str> = Ok("abc");
    let r1: Result<&str, &str> = Err("err");

    assert_eq!(s1.ok_or_else(fn_err), o1);
    assert_eq!(n.ok_or_else(fn_err), r1);

}

